/** 请求代理 
 * @author dongls 
*/
const colors = require('colors')
const axios = require('axios')
// utils
const { isNotLocalEnv } = require('../model/proxyConfigModel');
const http = require('http')
const https = require(isNotLocalEnv ? 'https' : 'http');
const { getRequestOptions, getProxyOptions, toJSON, getBody } = require('./HttpUtil');
import nodeProxyConfig from './NodeProxyConfig.js'


module.exports = {
  /** 
   * 发起一个请求,不能处理附件类请求
   * 如果请求地址需要登录，请在options的headers中传入对应的cookie
   * 
   * @param {*} path 请求路径
   * @param {*} method 请求方法
   * @param {*} rawBody 请求体
   * @param {*} options 
   */
  request(path, method, rawBody, options = {}){
    
    let requestOptions = getRequestOptions(path, method, options);
    
    // console.log(`${colors.bgYellow('request -> requestOptions')}`, requestOptions)
    delete requestOptions.headers['accept-encoding'];
    
    /** 
     * 之前的 http request headers 里面 accept-encoding 属性值有 gzip, deflate, br，表示可以解析这些编码类型。
     * 由于现在这个 node server 未做处理，不支持gzip，暂时参数简单粗暴的方式，将此属性删除。
     * 另一种处理方式：看下node原生api 有没有处理gzip的方式，处理下response 返回结果。
     * 其实我看有代码处理，不处理了，懒，不想弄，一行解决最方便。
    */
    delete requestOptions.headers['accept-encoding'];
    
    return new Promise((resolve, reject) => {
      let httpFnc = https;
      if(process.env.NODE_ENV !== 'production') httpFnc = http;
      let req = httpFnc.request(requestOptions, res => {
        let chunks = [];
        let size = 0;
        
        res.on('data', (chunk) => {
          chunks.push(chunk);
          size += chunk.length;
        })
        
        // 请求完成
        res.on('end', () => {
          // 拼接返回数据
          let body = Buffer.concat(chunks, size).toString();
          
          // 处理返回值
          let contentType = res.headers['content-type'];
          if (contentType && contentType.indexOf('application/json') > -1) {
            body = toJSON(body)
          }
        
          resolve(getBody(res, body, null));
        });
      })
      
      req.on('error', error => {
        console.log(error)
        resolve(getBody(null, null, error));
      });
      
      // 发送数据
      if (rawBody) req.write(rawBody);
      
      req.end();
    });
  },
  /**
   * 转发请求，无需对返回数据处理时用，可处理附件类请求
   * @param {*} ctx 
   * @param {*} options
   */
  proxy(ctx, options = {}) {
    let request = ctx.request;
    let response = ctx.response;
    let isHttp = options.httpProtocol === 'http'
    let protocol = isHttp ? http : https
    
    let rawBody = request.rawBody;
    let isMultipart = request.is('multipart/form-data');
    let proxyOptions = getProxyOptions(ctx, options)
    // --golbal-proxy 这里填本地的node代理地址
    const {host, hostname, port } = nodeProxyConfig;
    proxyOptions.host = host;
    proxyOptions.hostname = hostname;
    proxyOptions.port = port;
    delete proxyOptions.agent;

    // console.log(proxyOptions)
    
    /** 
     * 之前的 http request headers 里面 accept-encoding 属性值有 gzip, deflate, br，表示可以解析这些编码类型。
     * 由于现在这个 node server 未做处理，不支持gzip，暂时参数简单粗暴的方式，将此属性删除。
     * 另一种处理方式：看下node原生api 有没有处理gzip的方式，处理下response 返回结果。
     * 其实我看有代码处理，不处理了，懒，不想弄，一行解决最方便。
    */
    delete proxyOptions.headers['accept-encoding'];
    // console.log(`${colors.bgYellow('proxy -> proxyOptions')}`, proxyOptions);
    
    return new Promise((resolve, reject) => {
      let req = http.request(proxyOptions, res => {
        // 设定response的header
        let headers = res.headers;
        for(let name in headers) {
          response.set(name, headers[name])
        }
        
        // 设定请求状态
        response.status = res.statusCode;
        res.pipe(response.res, { end: false })
        
        res.on('end', () => {
          // 此处需要手动调用
          response.res.end()
          resolve()
        })
      })
      
      req.on('error', error => {
        console.log(error)
        reject(error)
      });
      
      // 非附件类请求需要调用end
      if (!isMultipart) {
        if (rawBody) req.write(rawBody)
        req.end();
        return
      }
      
      request.req.pipe(req)
    })
  },
  /**
   * 转发请求，无需对返回数据处理时用，
   * @param {*} ctx 上下文
   * @param {*} options 配置项
   */
  proxyForRender(ctx, options = {}) {
    let isHttp = true
    let proxyOptions = getProxyOptions(ctx, options)
    const {host, hostname, port } = nodeProxyConfig;
    proxyOptions.host = host;
    proxyOptions.hostname = hostname;
    proxyOptions.port = port;
    
    const AxiosConfig = {
      ...proxyOptions,
      url: `${isHttp ? 'http://' : 'https://'}${proxyOptions.hostname}:${proxyOptions.port}${proxyOptions.path}`
    }
    
    return new Promise((resolve, reject) => {
      axios(AxiosConfig)
        .then(function (response) {
          resolve(response.data)
        })
        .catch(function (error) {
          console.log(error)
          resolve('')
        })
    })
    
  }

};
